/* app_cfft_example. */

#include "app.h"
#include "app_fft_data.h"


/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

/*******************************************************************************
 * Code
 ******************************************************************************/

/*
* 使用CMSIS-DSP.
*/

/* 使用CMSIS-DSP计算浮点数的复数fft. */
void app_arm_cfft_f32_example(void)
{
    PRINTF("%s()\r\n", __func__);

    /* 以复数方式填充数组, 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_f32(fft_input_f32, FFT_INPUT_NUM_512);

    TimerCount_Start(); /* 开始计时. */
    /* 当使用arm_cfft_f32()计算时, 输入数组的内存单元将被计算的输出结果覆盖. */
    arm_cfft_f32(&arm_cfft_sR_f32_len512, fft_input_f32, 0, 1);
    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    /* 打印最终结果. */
    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %f, %f\r\n", i, fft_input_f32[i*2], fft_input_f32[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

/* 使用cmsis-dsp计算q31定点数复数fft. */
void app_arm_cfft_q31_example(void)
{
    PRINTF("%s()\r\n", __func__);

    /* 以复数方式填充数组, 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_q31(fft_input_q31, FFT_INPUT_NUM_512);

    /* cmsis-dsp在内部计算定点数时FFT时也除了N.
     * 此处为了同python和浮点数的计算结果一致, 先对输入数据放大以抵消算法中除以N的效果.
     */
    for (uint32_t i = 0u; i < FFT_INPUT_NUM_512*2; i++)
    {
        fft_input_q31[i] *= FFT_INPUT_NUM_512;
    }

    TimerCount_Start(); /* 开始计时. */

    arm_cfft_q31(&arm_cfft_sR_q31_len512, fft_input_q31, 0, 1);

    TimerCount_Stop(tick_counter_val); /* 结束计时. */
    /* 打印最终结果. */
    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_input_q31[i*2], fft_input_q31[i*2+1]);
    }

    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

/* 使用cmsis-dsp计算q15定点数复数fft. */
void app_arm_cfft_q15_example(void)
{
    PRINTF("%s()\r\n", __func__);

    /* 以复数方式填充数组, 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_q15(fft_input_q15, FFT_INPUT_NUM_512);

    /* cmsis-dsp在内部计算定点数FFT时也除了N.
     * 此处为了同python和浮点数的计算结果一致, 先对输入数据放大以抵消算法中除以N的效果.
     */
    for (uint32_t i = 0u; i < FFT_INPUT_NUM_512*2; i++)
    {
        fft_input_q15[i] *= FFT_INPUT_NUM_512;
    }

    TimerCount_Start(); /* 开始计时. */

    arm_cfft_q15(&arm_cfft_sR_q15_len512, fft_input_q15, 0, 1);

    TimerCount_Stop(tick_counter_val); /* 结束计时. */
    /* 打印最终结果. */
    for (uint32_t i = 0; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%4d]: %d, %d\r\n", i, fft_input_q15[i*2], fft_input_q15[i*2+1]);
    }

    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

/*
* PowerQuad的实现.
*/

/* 当前版本的FFT不直接支持浮点数的FFT.
 * 但是通过矩阵缩放计算, 利用PowerQuad硬件实现浮点数与定点数的转换, 在一定程度上也算是PowerQuad实现了浮点数FFT. */
void app_pq_cfft_f32_example(void)
{
    pq_config_t pq_config;

    PRINTF("%s()\r\n", __func__);

    /* 以复数方式填充数组, 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_f32(fft_input_f32, FFT_INPUT_NUM_512); /* 实际使用了FFT_INPUT_NUM*2的内存空间. */

    pq_config.inputAFormat = kPQ_Float;
    pq_config.inputAPrescale = 0;
    pq_config.outputFormat = kPQ_32Bit;
    pq_config.outputPrescale = 0;
    pq_config.machineFormat = kPQ_Float;
    PQ_SetConfig(POWERQUAD, &pq_config);

    TimerCount_Start(); /* 开始计时. */

    /* PowerQuad浮点数转定点数 */
    PQ_MatrixScale(POWERQUAD,
        POWERQUAD_MAKE_MATRIX_LEN(16, 16, 0), /* length = 256. */
        1.0f,
        (void *)fft_input_f32,
        (void *)fft_input_q31
        );
    PQ_WaitDone(POWERQUAD);
    PQ_MatrixScale(POWERQUAD,
        POWERQUAD_MAKE_MATRIX_LEN(16, 16, 0), /* length = 256. */
        1.0f,
        (void *)(fft_input_f32 + 256),
        (void *)(fft_input_q31 + 256)
        );
    PQ_WaitDone(POWERQUAD);
    PQ_MatrixScale(POWERQUAD,
        POWERQUAD_MAKE_MATRIX_LEN(16, 16, 0), /* length = 256. */
        1.0f,
        (void *)(fft_input_f32 + 512),
        (void *)(fft_input_q31 + 512)
        );
    PQ_WaitDone(POWERQUAD);
    PQ_MatrixScale(POWERQUAD,
        POWERQUAD_MAKE_MATRIX_LEN(16, 16, 0), /* length = 256. */
        1.0f,
        (void *)(fft_input_f32 + 768),
        (void *)(fft_input_q31 + 768)
        );
    PQ_WaitDone(POWERQUAD);

    /* 执行定点数FFT. */
    pq_config.inputAFormat = kPQ_32Bit;
    pq_config.inputAPrescale = 9; /* 抵消除以512的影响 */
    pq_config.outputFormat = kPQ_32Bit;
    pq_config.outputPrescale = 0;/* 乘以512. */
    pq_config.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_config.machineFormat = kPQ_32Bit;
    PQ_SetConfig(POWERQUAD, &pq_config);
    PQ_TransformCFFT(POWERQUAD,
        FFT_INPUT_NUM_512,
        fft_input_q31,
        fft_output_q31);
    PQ_WaitDone(POWERQUAD);

    /* PowerQuad定点数转浮点数. */
    pq_config.inputAFormat = kPQ_32Bit;
    pq_config.inputAPrescale = 0;
    pq_config.outputFormat = kPQ_Float;
    pq_config.outputPrescale = 0;
    pq_config.machineFormat = kPQ_Float;
    PQ_SetConfig(POWERQUAD, &pq_config);
    PQ_MatrixScale(POWERQUAD,
        POWERQUAD_MAKE_MATRIX_LEN(16, 16, 0), /* length = 256. */
        1.0f,
        (void *)fft_output_q31,
        (void *)fft_output_f32
        );
    PQ_WaitDone(POWERQUAD);
    PQ_MatrixScale(POWERQUAD,
        POWERQUAD_MAKE_MATRIX_LEN(16, 16, 0), /* length = 256. */
        1.0f,
        (void *)(fft_output_q31 + 256),
        (void *)(fft_output_f32 + 256)
        );
    PQ_WaitDone(POWERQUAD);
    PQ_MatrixScale(POWERQUAD,
        POWERQUAD_MAKE_MATRIX_LEN(16, 16, 0), /* length = 256. */
        1.0f,
        (void *)(fft_output_q31 + 512),
        (void *)(fft_output_f32 + 512)
        );
    PQ_WaitDone(POWERQUAD);
    PQ_MatrixScale(POWERQUAD,
        POWERQUAD_MAKE_MATRIX_LEN(16, 16, 0), /* length = 256. */
        1.0f,
        (void *)(fft_output_q31 + 768),
        (void *)(fft_output_f32 + 768)
        );
    PQ_WaitDone(POWERQUAD);

    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    for (uint32_t i = 0u; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%3d]: %f, %f\r\n", i, fft_output_f32[i*2], fft_output_f32[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

void app_pq_cfft_q31_example(void)
{
    pq_config_t pq_config;

    PRINTF("%s()\r\n", __func__);

    /* 以复数方式填充数组, 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_q31(fft_input_q31, FFT_INPUT_NUM_512);

    /* 执行定点数FFT. */
    pq_config.inputAFormat = kPQ_32Bit; /* 以32位带宽读取输入采样点数据. */
    pq_config.inputAPrescale = 9; /* 抵消除以512的影响 */
    pq_config.outputFormat = kPQ_32Bit; /* 以32位带宽输出计算结果. */
    pq_config.outputPrescale = 0;
    pq_config.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_config.machineFormat = kPQ_32Bit;
    PQ_SetConfig(POWERQUAD, &pq_config);

    TimerCount_Start(); /* 开始计时. */
    PQ_TransformCFFT(POWERQUAD,
        FFT_INPUT_NUM_512,
        fft_input_q31,
        fft_output_q31);
    PQ_WaitDone(POWERQUAD);

    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    for (uint32_t i = 0u; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%3d]: %d, %d\r\n", i, fft_output_q31[i*2], fft_output_q31[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}

void app_pq_cfft_q15_example(void)
{
    pq_config_t pq_config;

    PRINTF("%s()\r\n", __func__);

    /* 以复数方式填充数组, 实际使用了FFT_INPUT_NUM*2的内存空间. */
    app_init_cfft_input_q15(fft_input_q15, FFT_INPUT_NUM_512);

    /* 执行定点数FFT. */
    pq_config.inputAFormat = kPQ_16Bit; /* 以16位带宽读取输入采样点数据. */
    pq_config.inputAPrescale = 9; /* 抵消除以512的影响 */
    pq_config.outputFormat = kPQ_16Bit; /* 以16位带宽输出计算结果. */
    pq_config.outputPrescale = 0;
    pq_config.tmpBase = (uint32_t *)0xE0000000; /* private ram. */
    pq_config.machineFormat = kPQ_32Bit; /* 内部仍然使用32位数保存临时数据 */
    PQ_SetConfig(POWERQUAD, &pq_config);

    TimerCount_Start(); /* 开始计时. */
    PQ_TransformCFFT(POWERQUAD,
        FFT_INPUT_NUM_512,
        fft_input_q15,
        fft_output_q15);
    PQ_WaitDone(POWERQUAD);

    TimerCount_Stop(tick_counter_val); /* 结束计时. */

    for (uint32_t i = 0u; i < FFT_INPUT_NUM_512; i++)
    {
        PRINTF("[%3d]: %d, %d\r\n", i, fft_output_q15[i*2], fft_output_q15[i*2+1]);
    }
    PRINTF("done with %d us.\r\n\r\n", tick_counter_val/96u); /* 打印计算时间. */
}
/* EOF. */

